﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Utility;

namespace TCP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

        }
        private Socket ServerSocket = null;//服务端 
        private bool Flag_Listen = false;//监听客户端连接的标志
        public Dictionary<string, MySession> dic_ClientSocket = new Dictionary<string, MySession>();//tcp客户端字典
        private Dictionary<string, Thread> dic_ClientThread = new Dictionary<string, Thread>();//线程字典,每新增一个连接就添加一条线程
        IPAddress server_IP_selected = IPAddress.Any;
        int server_port_selected = 0;

        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="port">端口号</param>
        public bool OpenServer(IPAddress s_ip, int port)
        {
            try
            {
                Flag_Listen = true;
                // 创建负责监听的套接字，注意其中的参数；
                ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 创建包含ip和端口号的网络节点对象；
                IPEndPoint endPoint = new IPEndPoint(s_ip, port);
                try
                {
                    // 将负责监听的套接字绑定到唯一的ip和端口上；
                    ServerSocket.Bind(endPoint);
                }
                catch
                {
                    return false;
                }
                // 设置监听队列的长度；
                ServerSocket.Listen(100);
                // 创建负责监听的线程；
                Thread Thread_ServerListen = new Thread(ListenConnecting);
                Thread_ServerListen.IsBackground = true;
                Thread_ServerListen.Start();

                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 关闭服务
        /// </summary>
         public void CloseServer()
        {
            lock (dic_ClientSocket)
            {
                foreach (var item in dic_ClientSocket)
                {
                    item.Value.Close();//关闭每一个连接
                }
                dic_ClientSocket.Clear();//清除字典
            }
            lock (dic_ClientThread)
            {
                foreach (var item in dic_ClientThread)
                {
                    item.Value.Abort();//停止线程
                }
                dic_ClientThread.Clear();
            }
            Flag_Listen = false;
            //ServerSocket.Shutdown(SocketShutdown.Both);//服务端不能主动关闭连接,需要把监听到的连接逐个关闭
            if (ServerSocket != null)
                ServerSocket.Close();

        }

        /// <summary>
        /// 监听客户端请求的方法；
        /// </summary>
        private void ListenConnecting()
        {
            while (Flag_Listen)  // 持续不断的监听客户端的连接请求；
            {
                try
                {
                    Socket sokConnection = ServerSocket.Accept(); // 一旦监听到一个客户端的请求，就返回一个与该客户端通信的 套接字；
                                                                  // 将与客户端连接的 套接字 对象添加到集合中；
                    string str_EndPoint = sokConnection.RemoteEndPoint.ToString();

                    SetRecText("Obtain a connection request\r\n"+ str_EndPoint);

                    MySession myTcpClient = new MySession() 
                    { 
                        TcpSocket = sokConnection
                    };
                    //myTcpClient.TcpSocket = sokConnection;

                    //创建线程接收数据
                    Thread th_ReceiveData = new Thread(ReceiveData);
                    th_ReceiveData.IsBackground = true;
                    th_ReceiveData.Start(myTcpClient);
                    //把线程及客户连接加入字典
                    dic_ClientThread.Add(str_EndPoint, th_ReceiveData);
                    dic_ClientSocket.Add(str_EndPoint, myTcpClient);

                    UpdatecBoxRemoteIP();
                }
                catch
                {

                }
                Thread.Sleep(200);
            }
        }

        /// <summary>
        /// 不同的套接字对应各自独立的接收线程
        /// </summary>
        /// <param name="sokConnectionparn"></param>
        private void ReceiveData(object sokConnectionparn)
        {
            MySession tcpClient = sokConnectionparn as MySession;
            Socket socketClient = tcpClient.TcpSocket;
            bool Flag_Receive = true;

            while (Flag_Receive)
            {
                try
                {
                    // 定义一个2M的缓存区；
                    byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                    // 将接受到的数据存入到输入  arrMsgRec中；
                    int length = -1;
                    try
                    {
                        length = socketClient.Receive(arrMsgRec); // 接收数据，并返回数据的长度； 
                    }
                    catch
                    {
                        Flag_Receive = false;
                        // 从通信线程集合中删除被中断连接的通信线程对象；
                        string keystr = socketClient.RemoteEndPoint.ToString();
                        dic_ClientSocket.Remove(keystr);//删除客户端字典中该socket
                        dic_ClientThread[keystr].Abort();//关闭线程
                        dic_ClientThread.Remove(keystr);//删除字典中该线程

                        tcpClient = null;
                        socketClient = null;
                        break;
                    }
                    byte[] buf = new byte[length];
                    Array.Copy(arrMsgRec, buf, length);  
                    SetRecText("\r\n["+DateTime.Now.ToString()+"] Receive from " + socketClient.RemoteEndPoint.ToString()+ (isHexMode ? "RECV HEX>\r\n" + myConverter.GetHexString(buf,0,length): "RECV ASCII>\r\n" + System.Text.Encoding.Default.GetString(buf,0,length)));
                    lock (tcpClient.m_Buffer)
                    {
                        tcpClient.AddQueue(buf);
                    }
                }
                catch
                {

                }
                Thread.Sleep(100);
            }
        }

        /// <summary>
        /// 发送数据给指定的客户端
        /// 根据输入的远端地址，寻找对应的客户端套接字
        /// </summary>
        /// <param name="_endPoint">客户端套接字</param>
        /// <param name="_buf">发送的数组</param>
        /// <returns></returns>
        public bool SendData(string _endPoint, byte[] _buf)
        {
            MySession myT = new MySession();
            if (dic_ClientSocket.TryGetValue(_endPoint, out myT))
            {
                myT.Send(_buf);
                return true;
            }
            else
            {
                return false;
            }
        }



        #region   UI方面
        DataTable get_server_ip()
        {
            ///获取本地的IP地址
            string AddressIP = string.Empty;
            DataTable dt = new DataTable("Server IP");
            dt.Columns.Add("IP", Type.GetType("System.String"));
            DataRow dr1 = dt.NewRow();
            dr1["IP"] = "0.0.0.0";
            dt.Rows.Add(dr1);
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    DataRow dr = dt.NewRow();
                    dr["IP"] = _IPAddress.ToString();
                    dt.Rows.Add(dr);
                }
            }
            return dt;
        }
        DataTable get_remote_ip()
        {
            ///获取本地的IP地址
            string AddressIP = string.Empty;
            DataTable dt = new DataTable("Server IP");
            dt.Columns.Add("index", Type.GetType("System.String"));
            dt.Columns.Add("ip", Type.GetType("System.String"));
            dt.Columns.Add("port", Type.GetType("System.String"));
            dt.Columns.Add("all", Type.GetType("System.String"));

            int index = 0;
            foreach (var item in dic_ClientSocket)
            {
                DataRow dr = dt.NewRow();
                dr[0] = index++; 
                dr[1] = item.Key.ToString().Split(':')[0];
                dr[2] = item.Key.ToString().Split(':')[1];
                dr[3] = item.Key.ToString();
                dt.Rows.Add(dr);
            }
            return dt;
        }




        private void update_UI_cBoxServerIPList()
        {
            cBoxServerIPList.DataSource = get_server_ip();
            cBoxServerIPList.DisplayMember = "IP";
            //   cBoxServerIPList.SelectedIndex = 1;
        }


        private void cBoxServerIPList_DropDownClosed(object sender, EventArgs e)
        {
            System.Windows.Forms.ComboBox cb = sender as System.Windows.Forms.ComboBox;
            server_IP_selected = IPAddress.Parse(cb.Text);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            update_UI_cBoxServerIPList();
        }

        private void tBoxServerIPPoint_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!(char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
            {
                e.Handled = true;
            }
            else
            {
            }
        }

     
        private void btnTCPServerStartRec_Click(object sender, EventArgs e)
        {
            if (!Flag_Listen)
            {
                server_port_selected=Convert.ToInt32(tBoxServerIPPoint.Text.Trim());
                OpenServer(server_IP_selected, server_port_selected);
                btnTCPServerStartRec.Text = "关闭监听";
            }
            else
            {
                CloseServer();
                btnTCPServerStartRec.Text = "开始监听";
            }
        }
        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        delegate void SetRecTextCallback(string text);
        public void SetRecText(string text)
        {
            if (this.rTBoxServerRec.InvokeRequired)
            {
                SetRecTextCallback d = new SetRecTextCallback(SetRecText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.rTBoxServerRec.Text += text;
            }
        }
        delegate void UpdatecBoxRemoteIPCallback();
        public void UpdatecBoxRemoteIP()
        {
            if (this.cBoxRemoteIP.InvokeRequired)
            {
                UpdatecBoxRemoteIPCallback d = new UpdatecBoxRemoteIPCallback(UpdatecBoxRemoteIP);
                this.Invoke(d);
            }
            else
            {
                this.cBoxRemoteIP.DataSource = get_remote_ip();
                this.cBoxRemoteIP.DisplayMember = "all";
            }
        }

        private void btnUDPServerTransmit_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(rTBoxServerContent.Text))
            {
                if (Flag_Listen)
                {
                    SendData(cBoxRemoteIP.Text, isHexMode?myConverter.GetByteByInputHex (rTBoxServerContent.Text): System.Text.Encoding.Default.GetBytes(rTBoxServerContent.Text));
                } 
            }
        }
        bool isHexMode = false;
        private void ckBoxHex_CheckedChanged(object sender, EventArgs e)
        {
            isHexMode=ckBoxHex.Checked;
        }
    }
    #endregion
}
